;--------------------------------------------------
DA_DR	EQU 90h				;存在的只读数据段类型值
DA_DRW	EQU 92h				;存在的可读写数据段属性值
DA_DRWA	EQU	93h				;存在的已访问可读写数据段类型值
DA_C	EQU 98h				;存在的只执行代码段属性值
DA_CR	EQU	9Ah				;存在的可执行可读代码段属性值
DA_CCO	EQU	9Ch				;存在的只执行一致代码段属性值
DA_CCOR	EQU	9Eh				;存在的可执行可读一致代码段属性值
;-----------------------------------------------------
DA_32	EQU	4000h			;32位段

DA_DPL0		EQU	  00h	; DPL = 0
DA_DPL1		EQU	  20h	; DPL = 1
DA_DPL2		EQU	  40h	; DPL = 2
DA_DPL3		EQU	  60h	; DPL = 3
;------------------------------------------------------
%macro Descriptor 3
	dw	%2 & 0FFFFh				; 段界限 1				(2 字节)
	dw	%1 & 0FFFFh				; 段基址 1				(2 字节)
	db	(%1 >> 16) & 0FFh			; 段基址 2				(1 字节)
	dw	((%2 >> 8) & 0F00h) | (%3 & 0F0FFh)	; 属性 1 + 段界限 2 + 属性 2		(2 字节)
	db	(%1 >> 24) & 0FFh			; 段基址 3				(1 字节)
%endmacro 

org	07c00h
	jmp	LABEL_BEGIN

[SECTION .gdt]
; GDT
;                                         段基址,      段界限     			, 属性
LABEL_GDT:			Descriptor				0,			0,					0					;空描述符
LABEL_DESC_CODE32:	Descriptor				0,			SegCode32Len - 1,	DA_32 + DA_C		;非一致代码段，32
LABEL_DESC_VIDEO:	Descriptor			0B8000h,		0ffffh,				DA_DRW				;显存首地址
; GDT 结束


GdtLen equ	$-LABEL_GDT					;GDT长度
GdtPtr	dw	GdtLen - 1					;GDT界限
		dd	0							;GDT基地址
		
		
;	GDT选择子
SelectorCode32	equ		LABEL_DESC_CODE32 - LABEL_GDT
SelectorVideo	equ		LABEL_DESC_VIDEO - LABEL_GDT
; END of [SECTION .gdt]

[SECTION .s16]
[BITS	16]
LABEL_BEGIN:
	mov ax,cs
	mov ds,ax
	mov es,ax
	mov ss,ax
	mov sp,0100h
	
	; 初始化 32 位代码段描述符
	xor eax,eax
	mov ax,cs
	shl eax,4
	add eax,LABEL_SEG_CODE32
	mov word [LABEL_DESC_CODE32 + 2], ax
	shr eax, 16
	mov byte [LABEL_DESC_CODE32 + 4], al
	mov byte [LABEL_DESC_CODE32 + 7], ah
	
	;未加载GDTR做准备
	xor eax, eax
	mov ax,ds
	shl eax,4
	add eax,LABEL_GDT			; eax <- gdt 基地址
	mov dword [GdtPtr + 2], eax		; [GdtPtr + 2] <- gdt 基地址
	
	;加载GDTR
	lgdt [GdtPtr]
	
	;关中断
	cli
	
	;打开地址线A20
	in al, 92h
	or al,00000010b
	out 92h,al
	
	;准备切换到保护模式
	mov eax,cr0
	or eax,1
	mov cr0,eax
	
	;真正进入保护模式
	jmp dword SelectorCode32:0				;执行这一句会把 SelectorCode32 装入 cs, 并跳转到 Code32Selector:0  处
	
	
	; END of [SECTION .s16]
	
	
; 32 位代码段. 由实模式跳入.
[SECTION .s32]
[BITS 32]
	
LABEL_SEG_CODE32:
	mov ax,SelectorVideo
	mov gs,ax			;视频段选择子
		
	mov edi,(80 * 3 + 0) * 2			;屏幕第 3 行, 第 0 列。
	mov ah, 0ch							; 0000: 黑底    1100: 红字
	mov al, '!'
	mov [gs:edi], ax
		
	;结束
	jmp $
		
		
SegCode32Len	equ	$ - LABEL_SEG_CODE32
; END of [SECTION .s32]
times 361	db 0
dw 0xaa55